<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<html><head><title>Programming in Lua : 28.1</title>
<link rel="stylesheet" type="text/css" href="pil.css">
</head>
<body>
<p class="warning">
<A HREF="contents.html"><IMG TITLE="Programming in Lua (first edition)" SRC="capa.jpg" ALT="" ALIGN="left"></A>This first edition was written for Lua 5.0. While still largely relevant for later versions, there are some differences.<BR>The third edition targets Lua 5.2 and is available at <A HREF="http://www.amazon.com/exec/obidos/ASIN/859037985X/theprogrammil3-20">Amazon</A> and other bookstores.<BR>By buying the book, you also help to <A HREF="../donations.html">support the Lua project</A>.
</p>
<table width="100%" class="nav">
<tr>
<td width="10%" align="left"><a href="28.html"><img border="0" src="left.png" alt="Previous"></a></td>
<td width="80%" align="center"><a href="contents.html"><font face="Helvetica,Arial,sanserif">
<font color="gray">Programming in </font><font color="blue"> Lua</font>
</font></a></td>
<td width="10%" align="right"><a href="28.2.html"><img border="0" src="right.png" alt="Next"></a></td>
</tr>
<tr>
<td width="10%" align="left"></td>
<td width="80%" align="center"><a href="contents.html#P4">Part IV. The C API</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<a href="contents.html#28">Chapter 28. User-Defined Types in C</a></td>
<td width="10%" align="right"></td></tr>
</table>
<hr/>
<p><h2>28.1 &ndash; Userdata</h2>

<p>Our first concern is how to represent array values in Lua.
Lua provides a basic type specifically for this:
<em>userdata</em>.
A userdatum offers a raw memory area
with no predefined operations in Lua.

<p>The Lua API offers the following function to create
a userdatum:
<pre>
    void *lua_newuserdata (lua_State *L, size_t size);
</pre>
The <code>lua_newuserdata</code> function allocates a block of memory
with the given size,
pushes the corresponding userdatum on the stack,
and returns the block address.
If for some reason you need to allocate memory by other means,
it is very easy to create a userdatum with the size of a pointer
and to store there a pointer to the real memory block.
We will see examples of this technique in the next chapter.

<p>Using <code>lua_newuserdata</code>,
the function that creates new arrays is as follows:
<pre>
    static int newarray (lua_State *L) {
      int n = luaL_checkint(L, 1);
      size_t nbytes = sizeof(NumArray) + (n - 1)*sizeof(double);
      NumArray *a = (NumArray *)lua_newuserdata(L, nbytes);
      a->size = n;
      return 1;  /* new userdatum is already on the stack */
    }
</pre>
(The <code>luaL_checkint</code> function
is a variant of <code>luaL_checknumber</code> for integers.)
Once <code>newarray</code> is registered in Lua,
you can create new arrays with a statement like
<code>a = array.new(1000)</code>.

<p>To store an entry,
we will use a call like <code>array.set(array, index, value)</code>.
Later we will see how to use metatables to support the more conventional
syntax <code>array[index] = value</code>.
For both notations, the underlying function is the same.
It assumes that indices start at 1, as is usual in Lua.
<pre>
    static int setarray (lua_State *L) {
      NumArray *a = (NumArray *)lua_touserdata(L, 1);
      int index = luaL_checkint(L, 2);
      double value = luaL_checknumber(L, 3);
    
      luaL_argcheck(L, a != NULL, 1, "`array' expected");
    
      luaL_argcheck(L, 1 &lt;= index &amp;&amp; index &lt;= a->size, 2,
                       "index out of range");
    
      a->values[index-1] = value;
      return 0;
    }
</pre>
The <code>luaL_argcheck</code> function checks a given condition,
raising an error if necessary.
So, if we call <code>setarray</code> with a bad argument,
we get an elucidative error message:
<pre>
    array.set(a, 11, 0)
    --> stdin:1: bad argument #1 to `set' (`array' expected)
</pre>

<p>The next function retrieves an entry:

<pre>
    static int getarray (lua_State *L) {
      NumArray *a = (NumArray *)lua_touserdata(L, 1);
      int index = luaL_checkint(L, 2);
    
      luaL_argcheck(L, a != NULL, 1, "`array' expected");
    
      luaL_argcheck(L, 1 &lt;= index &amp;&amp; index &lt;= a->size, 2,
                       "index out of range");
    
      lua_pushnumber(L, a->values[index-1]);
      return 1;
    }
</pre>
We define another function to retrieve the size of an array:
<pre>
    static int getsize (lua_State *L) {
      NumArray *a = (NumArray *)lua_touserdata(L, 1);
      luaL_argcheck(L, a != NULL, 1, "`array' expected");
      lua_pushnumber(L, a->size);
      return 1;
    }
</pre>
Finally, we need some extra code to initialize our library:
<pre>
    static const struct luaL_reg arraylib [] = {
      {"new", newarray},
      {"set", setarray},
      {"get", getarray},
      {"size", getsize},
      {NULL, NULL}
    };
    
    int luaopen_array (lua_State *L) {
      luaL_openlib(L, "array", arraylib, 0);
      return 1;
    }
</pre>
Again, we use <code>luaL_openlib</code>, from the auxiliary library.
It creates a table with the given name (<code>"array"</code>, in our example)
and fills it with the pairs name-function specified by the
array <code>arraylib</code>.

<p>After opening the library,
we are ready to use our new type in Lua:
<pre>
    a = array.new(1000)
    print(a)               --> userdata: 0x8064d48
    print(array.size(a))   --> 1000
    for i=1,1000 do
      array.set(a, i, 1/i)
    end
    print(array.get(a, 10))  --> 0.1
</pre>

<p>Running this implementation on a Pentium/Linux,

an array with 100K elements takes 800 KB of memory, as expected;
an equivalent Lua table needs more than 1.5 MB.

<hr/>
<table width="100%" class="nav">
<tr valign="top">
<td width="90%" align="left">
<small>
  Copyright &copy; 2003&ndash;2004 Roberto Ierusalimschy.  All rights reserved.
</small>
</td>
<td width="10%" align="right"><a href="28.2.html"><img border="0" src="right.png" alt="Next"></a></td>
</tr>
</table>


</body></html>

